<?php

namespace App\Services;

use App\Models\College;
use App\Models\YikaoSchoolScore;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use GuzzleHttp\Client;


class SchoolScoreSpiderService
{
    /**
     * 代理配置
     *
     * @var bool
     */
    protected $proxyEnabled;

    /**
     * @var Logger
     */
    protected $logger;
    protected $httpClient;
    protected $config;
    protected $delay;

    /**
     * 构造函数
     *
     * @param bool $proxyEnabled 是否启用代理
     * @param array $config 服务配置数组
     * @param int $delay 每次请求之间的延迟时间(秒)
     */
    public function __construct(bool $proxyEnabled = false, array $config = [], int $delay = 0)
    {
        $this->proxyEnabled = $proxyEnabled;
        $logDir = __DIR__ . '/../../storage/logs';
        if (!is_dir($logDir)) {
            mkdir($logDir, 0777, true);
        }
        $this->logger = new Logger('school-score-spider');
        $this->logger->pushHandler(new StreamHandler($logDir . '/school-score-spider.log', Logger::DEBUG));
        
        $options = [
            'headers' => [
                'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
            ],
            'timeout' => 30,
            // 'proxy' => "http://host.docker.internal:1082"
            'proxy' => "http://127.0.0.1:1080"
        ];
        
        $this->httpClient = new Client($options);
    }

    /**
     * 处理院校分数采集
     *
     * @param int $limit 限制采集数量
     * @return array 采集统计信息
     */
    public function processSchoolScore(int $limit = 0): array
    {
        $stats = ['total' => 0, 'success' => 0, 'failed' => 0];

        echo "开始获取省份年份数据...\n";

        // 1. 获取省份年份数据
        $provinceYearData = $this->getProvinceYearData();
        if (empty($provinceYearData)) {
            $this->logger->error('获取省份年份数据失败');
            echo "获取省份年份数据失败\n";
            return $stats;
        }

        echo "获取到省份年份数据: " . count($provinceYearData) . "个省份\n";

        // 2. 获取院校列表
        $colleges = College::query()
            ->when($limit > 0, function ($query) use ($limit) {
                $query->limit($limit);
            })
            ->where('status', 0)
            ->get(['id', 'school_id', 'college_name']);

        $totalColleges = count($colleges);
        echo "开始处理 {$totalColleges} 所院校的分数数据...\n";

        foreach ($colleges as $index => $college) {
            if ($this->delay > 0) {
                echo "等待 {$this->delay} 秒...\n";
                sleep($this->delay);
            }
            $stats['total']++;
            $progress = round(($index + 1) / $totalColleges * 100);
            echo "处理进度: [{$progress}%] 院校ID: {$college->school_id} 院校名称：{$college->college_name}\n";

            try {
                // 3. 处理每个院校的分数数据
                $result = $this->withRetry(
                    function () use ($college, $provinceYearData) {
                        return $this->processSingleSchool($college, $provinceYearData);
                    },
                    3,
                    '院校分数采集',
                    ['school_id' => $college->school_id]
                );

                if ($result) {
                    $stats['success']++;
                    echo "成功处理院校: {$college->school_id}\n";
                } else {
                    $stats['failed']++;
                    $this->logger->error("院校分数采集失败: school_id={$college->school_id}");
                    echo "处理失败: {$college->school_id}\n";
                }
            } catch (\Exception $e) {
                $stats['failed']++;
                $this->logger->error("院校分数采集异常: school_id={$college->school_id}, error=" . $e->getMessage());
                echo "处理异常: {$college->school_id} - {$e->getMessage()}\n";
            }
        }

        echo "处理完成: 成功 {$stats['success']}, 失败 {$stats['failed']}, 总计 {$stats['total']}\n";

        return $stats;
    }

    /**
     * 处理单个院校的分数数据
     *
     * @param College $college 院校对象
     * @param array $provinceYearData 省份年份数据
     * @return bool 是否成功
     */
    protected function processSingleSchool(College $college, array $provinceYearData): bool
    {
        $success = true;
        $totalProvinces = count($provinceYearData);
        $processedProvinces = 0;

        echo "开始处理院校 {$college->school_id} 的分数数据 ({$totalProvinces}个省份)...\n";

        foreach ($provinceYearData as $provinceId => $years) {
            echo "等待 1 秒...\n";
            sleep(1);

            $processedProvinces++;
            $totalYears = count($years);
            $processedYears = 0;

            echo "处理省份 {$provinceId} ({$processedProvinces}/{$totalProvinces})...\n";

            foreach ($years as $year) {
                $processedYears++;
                $url = "https://static-data.gaokao.cn/www/2.0/schoolprovincescore/{$college->school_id}/{$year}/{$provinceId}.json?a=www.gaokao.cn";

                echo "获取 {$year} 年数据 ({$processedYears}/{$totalYears})...\n";

                try {
                    $response = $this->withRetry(
                        function () use ($url) {
                            return $this->fetchScoreData($url);
                        },
                        3,
                        '获取院校分数API',
                        ['url' => $url]
                    );

                    if ($response && $response['code'] === '0000') {
                        $this->saveScoreData($college->school_id, $response['data']);
                        echo "成功保存 {$year} 年数据\n";
                    } else {
                        $success = false;
                        $this->logger->warning("院校分数API返回异常: school_id={$college->school_id}, province_id={$provinceId}, year={$year}");
                        echo "API返回异常: {$year} 年\n";
                    }
                } catch (\Exception $e) {
                    $success = false;
                    $this->logger->error("院校分数采集异常: school_id={$college->school_id}, province_id={$provinceId}, year={$year}, error=" . $e->getMessage());
                    echo "处理异常: {$year} 年 - {$e->getMessage()}\n";
                }
            }
        }

        $status = $success ? '成功' : '部分失败';

        $this->updateCollegeStatus($college->school_id);

        echo "院校 {$college->school_id} 处理完成: {$status}\n";

        return $success;
    }

    /**
     * 获取省份年份数据
     *
     * @return array
     */
    protected function getProvinceYearData(): array
    {

        $filePath = dirname(__DIR__) . '/../public/data/provincescore.json';
        // '/www/college/public/data/provincescore.json';
        if (!\App\Helpers\FileHelper::exists($filePath)) {
            $this->logger->error("省份年份数据文件不存在: {$filePath}");
            return [];
        }

        $content = \App\Helpers\FileHelper::get($filePath);
        $data = json_decode($content, true);
        return $data['newsdata']['year'] ?? [];
    }

    /**
     * 获取院校分数数据
     *
     * @param string $url API地址
     * @return array|null
     */
    protected function fetchScoreData(string $url): ?array
    {
        try {
            $shortUrl = preg_replace('/https?:\/\/([^\/]+).*/', '$1', $url);
            echo "请求API: {$shortUrl}...\n";

            $response = $this->httpClient->get($url);
            $statusCode = $response->getStatusCode();

            echo "响应状态: {$statusCode} " . ($statusCode === 200 ? "成功" : "失败") . "\n";

            if ($statusCode === 200) {
                return json_decode($response->getBody()->getContents(), true);
            }
            return null;
        } catch (\Exception $e) {
            $this->logger->error("获取分数数据失败: {$url}, error=" . $e->getMessage());
            echo "请求异常: " . $e->getMessage() . "\n";
            return null;
        }
    }

    /**
     * 保存分数数据
     *
     * @param int $schoolId 院校ID
     * @param array $data 分数数据
     * @return void
     */
    protected function saveScoreData(int $schoolId, array $data): void
    {
        foreach ($data as $keyIndex => $scoreData) {
            foreach ($scoreData['item'] as $item) {
                $item['key_index'] = $keyIndex;
                $item['school_id'] = $schoolId;

                YikaoSchoolScore::updateOrCreate(
                    [
                        'school_id' => $schoolId,
                        'province_id' => $item['province_id'],
                        'year' => $item['year'],
                        'type' => $item['type'],
                        'batch' => $item['batch']
                    ],
                    $item
                );
            }
        }
    }

    /**
     * 带重试的执行方法
     *
     * @param callable $func 执行函数
     * @param int $maxAttempts 最大尝试次数
     * @param string $actionName 操作名称
     * @param array $context 上下文信息
     * @return mixed
     */
    protected function withRetry(callable $func, int $maxAttempts, string $actionName, array $context = [])
    {
        $attempts = 0;
        $lastError = null;

        while ($attempts < $maxAttempts) {
            try {
                return $func();
            } catch (\Exception $e) {
                $lastError = $e;
                $attempts++;
                $this->logger->warning("{$actionName} 第{$attempts}次失败", $context + ['error' => $e->getMessage()]);

                if ($attempts < $maxAttempts) {
                    sleep(1); // 简单的重试间隔
                }
            }
        }

        throw $lastError ?? new \RuntimeException("{$actionName} 重试{$maxAttempts}次后失败");
    }

    public function updateCollegeStatus(int $collegeId): int
    {
        return College::query()->where('school_id', $collegeId)->update(['status' => 1]);
    }
}
